<template>
  <el-row :gutter="gutter">
    <el-form
      class="XForm"
      ref="XForm"
      v-loading="loading"
      v-if="isXForm"
      :model="formData"
      :rules="formRulesData"
      :size="size"
      :label-position="labelPosition"
      :label-width="labelWidth">
      <el-col v-if="error" :span="24">
        <div style="background: #FEF0F0;color: #F57171;padding: 10px">
          {{error}}
          <el-link href='https://fhs1.gitee.io/x-tool/#/组件/xform?id=dataKey' target="_blank" type="primary" :underline="false">详情</el-link>
        </div>
        <br>
      </el-col>
      <el-col
        v-for="(item, index) in formList"
        :key="index"
        :span="item.span === undefined ? 12 : item.span"
        :xs="item.attrs.xs === undefined ? undefined : item.attrs.xs"
        :sm="item.attrs.sm === undefined ? undefined : item.attrs.sm"
        :md="item.attrs.md === undefined ? undefined : item.attrs.md"
        :lg="item.attrs.lg === undefined ? undefined : item.attrs.lg"
        :xl="item.attrs.xl === undefined ? undefined : item.attrs.xl">
        <!-- 组件 -->
        <el-form-item
          :label="item.label"
          :prop="item.prop"
          :style="item.style"
          :label-width="item.attrs ? item.attrs.labelWidth ? item.attrs.labelWidth : labelWidth : labelWidth">
          <span slot="label">{{ item.label }}&nbsp;&nbsp;<span
            v-if="item.tips"
            style="color: #909399">({{ item.tips }})</span></span>
          <slot
            ref="XSlot"
            v-if="item.slot"
            :name="item.slot"
            :label="item.label"
            :prop="item.prop"
            :typex="item.type"
            :index="index"
            :disabled="item.disabled"
            :options="item.options"
            :action="item.action"
            :attrs="item.attrs"
            :reset="{click:() => resetFields()}"
            :validate="{click:() => validate(() => {})}"
            :binds="binds(item)" />
          <component
            v-else
            ref="XComponent"
            :is="item.template ? item.template : item.type === undefined ? 'XInput' : item.type"
            :_ref="$refs['XForm']"
            :_this="$parent"
            :value.sync="formData[item.prop]"
            @valueChange="valueChange($event, index)"
            @blur="blur($event, index)"
            @click="click($event, index)"
            :label="item.label"
            :prop="item.prop"
            :typex="item.type"
            :index="index"
            :disabled="item.disabled"
            :options="item.options"
            :action="item.action"
            :attrs="item.attrs" />
        </el-form-item>
      </el-col>
    </el-form>
  </el-row>
</template>
<script>
import {
  XInput,
  XDate,
  XDateTime,
  XSelect,
  XSwitch,
  XCheckbox,
  XRadio,
  XTextarea,
  XRichText,
  XFiles2,
  XCity,
  XCascader,
  XInputNumber,
  XRate,
  XColor,
  XSlider,
  XNation,
  XFiles
} from '../X'
import XUtils from './XUtils'
export default {
  components: {
    XInput,
    XDate,
    XDateTime,
    XSelect,
    XSwitch,
    XCheckbox,
    XRadio,
    XTextarea,
    XRichText,
    XFiles2,
    XCity,
    XCascader,
    XInputNumber,
    XRate,
    XColor,
    XSlider,
    XNation,
    XFiles
  },
  data () {
    return {
      isXForm: true,
      formRulesData: {},
      error: ''
    }
  },
  watch: {
    formList: function (newFormList) {
      if (newFormList.length !== 0) {
        this.initFormData()
        this.initFormListRules()
      }
      this.formList.forEach(item => {
        if (item.attrs === undefined) {
          item.attrs = {}
        }
      })
    },
    formRules: function () {
      this.initFormListRules()
    }
  },
  created () {
    this.formList.forEach(item => {
      if (item.attrs === undefined) {
        item.attrs = {}
      }
    })
    this.initFormListRules()
    this.initFormData()
  },
  props: {
    loading: { type: Boolean, default: false },
    dataKey: { type: String, default: 'formData' },
    formData: {
      type: Object,
      required: true
    },
    formRules: {
      type: Object,
      default: _ => ({})
    },
    formList: {
      type: Array,
      required: true
    },
    size: {
      type: String,
      default: 'small'
    },
    labelPosition: {
      type: String,
      default: 'left'
    },
    labelWidth: {
      type: String,
      default: '80px'
    },
    gutter: {
      type: Number,
      default: 30
    }
  },
  computed: {
    binds () {
      return function (item) {
        let binds = {}
        if (item.type === 'XInput') {
          binds.placeholder = item.attrs.placeholder ? item.attrs.placeholder : `请输入${item.label}`
          binds.disabled = item.disabled
          binds.style = 'width: 100%;'
        } else if (item.type === 'XSelect') {
          binds.placeholder = item.attrs.placeholder ? item.attrs.placeholder : `请选择${item.label}`
          binds.disabled = item.disabled
          binds.style = 'width: 100%;'
        }
        return binds
      }
    }
  },
  methods: {
    valueChange (val, index) {
      // this.formData[index] = val
      this.formData[this.formList[index].prop] = val
      if (this.formList[index].change) {
        this.formList[index].change(val, this.formList[index].prop)
      }
    },
    click (val, index) {
      if (this.formList[index].click) {
        this.formList[index].click(val, this.formList[index].prop)
      }
    },
    blur (val, index) {
      if (this.formList[index].blur) {
        this.formList[index].blur(val, this.formList[index].prop)
      }
    },
    /**
     * 自动初始化 formData
     */
    initFormData () {
      let _this = this.$parent
      let isInit = false
      while (_this) {
        if (_this[this.dataKey]) {
          this.error = ''
          _this[this.dataKey] = XUtils.initFormData(this.formList, _this[this.dataKey])
          isInit = true
          break
        } else _this = _this.$parent
      }
      if (!isInit) {
        let propArr = this.formList.filter(e => e.prop)
        for (let index = 0; index < propArr.length; index++) {
          if (!(propArr[index].prop in this.formData)) {
            this.error = 'XForm 严重错误提醒 请正确指定 dataKey'
            console.error(this.error)
            break
          }
        }
      }
    },
    /**
     * 初始化表单验证规则
     */
    initFormListRules () {
      this.formRulesData = XUtils.deepClone(this.formRules)
      this.$nextTick(() => {
        this.formList.forEach(item => {
          if (item.rules) {
            item.rules.forEach(it => {
              if (this.formRulesData[item.prop] === undefined) { this.formRulesData[item.prop] = [] }
              const itemRules = this.formRulesData[item.prop]

              // const inputTypeArr = [undefined, 'XInput', 'XInputNumber', 'XRichText']
              // let findIndex = inputTypeArr.findIndex(inputTypeArr)

              // console.log('规则', item)

              let regexMes = '输入'

              // 必填验证
              if (it.isNull) {
                let message = it.message ? it.message : `请${regexMes}${item.label}`
                itemRules.push({ required: true, message, trigger: item.trigger ? item.trigger : 'blur' })
              }
              if (it.regex) { // 正则验证
                let message = it.message ? it.message : `请${regexMes}正确${item.label}`
                let validator = (rule, value, callback) => {
                  if (value === undefined || value === '') callback()
                  const regex = it.regex
                  if (!regex.test(value)) {
                    callback(new Error(message))
                  }
                  callback()
                }
                itemRules.push({ validator, trigger: 'change' })
              }
              if (it.validator) { // validator 验证
                itemRules.push({ validator: it.validator, trigger: item.trigger ? item.trigger : 'blur' })
              }
              if (it.max || it.min) {
                if (!it.message) { it.message = `请${regexMes}正确${item.label}` }
                itemRules.push({ ...it, trigger: item.trigger ? item.trigger : 'blur' })
              }
            })
          }
        })
      })
      this.refreshXForm()
    },
    /**
     * 表单校验
     */
    validate (callback) {
      if (this.formList.length === 0) { return new Error('error formList 字段没有可验证的控件') }
      let is = true
      this.$refs['XForm'].validate(valid => {
        // 创建之前钩子
        for (let index = 0; index < this.formList.length; index++) {
          const item = this.formList[index]
          if (item.beforeValidate) {
            if (item.beforeValidate() === false) {
              is = false; callback(is)
              return false
            }
          }
        }
        if (!valid) {
          is = false; callback(is)
          return false
        }
        is = true; callback(is)
      })
    },
    /**
     * 重置表单
     */
    resetFields () {
      for (let index = 0; index < this.formList.length; index++) {
        const item = this.formList[index]
        if (item.prop === undefined) { continue }
        const arrayArr = ['XCheckbox', 'XFiles', 'XFiles2']
        const numberArr = ['XRate', 'XSlider']
        if (numberArr.indexOf(item.type) > -1 || (item.attrs && item.xType === Number) || item.xType === Number) {
          this.formData[item.prop] = 0
        } else if (arrayArr.indexOf(item.type) > -1 || (item.attrs && item.xType === Array) || item.xType === Array) {
          this.formData[item.prop] = []
        } else {
          this.formData[item.prop] = undefined
        }
      }
      this.initFormListRules()
    },
    refreshXForm () {
      this.isXForm = false
      this.$nextTick(() => {
        this.isXForm = true
      })
    }
  }
}
</script>
<style scoped>
.XForm {
  display: flex;
  flex-wrap: wrap;
}
</style>
